"""
AI Classification Engine Main Application

Main application for running the AI Classification Engine with all components
integrated for production use with the ArXiv subscription platform.
"""

import logging
import json
import sys
import time
from pathlib import Path
from typing import Dict, Any, Optional
import argparse
from datetime import datetime

# Import AI Classification Engine components
from .core.classification_engine import AIClassificationEngine
from .core.recommendation_engine import PersonalizedRecommendationEngine
from .core.paper_classifier import SemanticPaperClassifier
from .learning.user_preference_learner import UserPreferenceLearner
from .learning.feedback_system import FeedbackLearningSystem
from .embeddings.similarity_engine import SemanticSimilarityEngine
from .batch.batch_processor import BatchClassificationProcessor
from .realtime.realtime_classifier import RealtimeClassifier
from .utils.scoring import RecommendationScorer

# Import database manager (assuming it exists in the parent system)
try:
    from arxiv_scraper_service.core.database_manager import DatabaseManager
except ImportError:
    print("Warning: Database manager not available. Some features will be disabled.")
    DatabaseManager = None


class AIClassificationApplication:
    """
    Main application class for the AI Classification Engine.
    
    Provides a unified interface for all classification and recommendation
    functionality with proper initialization, configuration management,
    and service orchestration.
    """
    
    def __init__(self, config_path: Optional[str] = None):
        """Initialize the AI Classification Application.
        
        Args:
            config_path: Path to configuration file
        """
        # Load configuration
        self.config = self._load_config(config_path)
        
        # Setup logging
        self._setup_logging()
        self.logger = logging.getLogger(__name__)
        
        # Initialize database connection
        self.db = self._init_database()
        
        # Initialize AI components
        self.components = {}
        self._init_components()
        
        # Application state
        self.is_running = False
        self.services_started = []
        
        self.logger.info("AI Classification Application initialized")
    
    def _load_config(self, config_path: Optional[str]) -> Dict[str, Any]:
        """Load configuration from file or use defaults."""
        
        default_config = {
            "version": "1.0.0",
            "database": {
                "host": "localhost",
                "port": 5432,
                "database": "arxiv_platform",
                "user": "arxiv_user",
                "password": "password"
            },
            "embedding": {
                "model_name": "all-MiniLM-L6-v2",
                "use_gpu": False,
                "batch_size": 32,
                "cache_embeddings": True,
                "max_cache_size": 10000
            },
            "learning": {
                "time_decay_factor": 0.95,
                "min_interactions": 5,
                "cache_expiry_hours": 24
            },
            "feedback": {
                "learning_rate": 0.01,
                "feedback_decay_days": 90,
                "min_feedback_count": 5
            },
            "scoring": {
                "scoring_weights": {
                    "semantic_similarity": 0.35,
                    "category_match": 0.25,
                    "author_preference": 0.15,
                    "novelty_score": 0.10,
                    "popularity_score": 0.05,
                    "diversity_bonus": 0.10
                },
                "novelty_decay_days": 30,
                "diversity_threshold": 0.7
            },
            "batch_processing": {
                "batch_size": 50,
                "max_workers": 4,
                "retry_attempts": 3,
                "timeout_seconds": 3600
            },
            "realtime": {
                "realtime_threads": 2,
                "queue_size": 1000,
                "realtime_batch_size": 5,
                "processing_timeout": 300
            },
            "logging": {
                "level": "INFO",
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
                "file": "ai_classification.log"
            }
        }
        
        if config_path and Path(config_path).exists():
            try:
                with open(config_path, 'r') as f:
                    file_config = json.load(f)
                
                # Merge configurations (file config overrides defaults)
                config = default_config.copy()
                config.update(file_config)
                return config
                
            except Exception as e:
                print(f"Error loading config file: {e}")
                print("Using default configuration")
        
        return default_config
    
    def _setup_logging(self):
        """Setup logging configuration."""
        log_config = self.config.get('logging', {})
        
        # Configure root logger
        logging.basicConfig(
            level=getattr(logging, log_config.get('level', 'INFO')),
            format=log_config.get('format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s'),
            filename=log_config.get('file'),
            filemode='a'
        )
        
        # Also log to console
        console_handler = logging.StreamHandler()
        console_handler.setLevel(getattr(logging, log_config.get('level', 'INFO')))
        formatter = logging.Formatter(log_config.get('format'))
        console_handler.setFormatter(formatter)
        
        root_logger = logging.getLogger()
        root_logger.addHandler(console_handler)
    
    def _init_database(self) -> Optional[Any]:
        """Initialize database connection."""
        if not DatabaseManager:
            self.logger.warning("Database manager not available")
            return None
        
        try:
            db_config = self.config.get('database', {})
            db_manager = DatabaseManager(db_config)
            db_manager.connect()
            
            self.logger.info("Database connection established")
            return db_manager
            
        except Exception as e:
            self.logger.error(f"Failed to initialize database: {e}")
            return None
    
    def _init_components(self):
        """Initialize all AI classification components."""
        
        # Core classification engine
        self.components['classification_engine'] = AIClassificationEngine(
            self.config, self.db
        )
        
        # Paper classifier
        self.components['paper_classifier'] = SemanticPaperClassifier(self.config)
        
        # User preference learner
        self.components['preference_learner'] = UserPreferenceLearner(
            self.config.get('learning', {}), self.db
        )
        
        # Feedback learning system
        self.components['feedback_system'] = FeedbackLearningSystem(
            self.config.get('feedback', {}), self.db
        )
        
        # Semantic similarity engine
        self.components['similarity_engine'] = SemanticSimilarityEngine(
            self.config.get('embedding', {})
        )
        
        # Recommendation scorer
        self.components['recommendation_scorer'] = RecommendationScorer(
            self.config.get('scoring', {})
        )
        
        # Recommendation engine
        self.components['recommendation_engine'] = PersonalizedRecommendationEngine(
            self.config, self.db
        )
        
        # Batch processor
        self.components['batch_processor'] = BatchClassificationProcessor(
            self.config, self.db
        )
        
        # Real-time classifier
        self.components['realtime_classifier'] = RealtimeClassifier(
            self.config, self.db
        )
        
        self.logger.info("All AI components initialized successfully")
    
    def start_services(self, services: Optional[list] = None):
        """
        Start AI classification services.
        
        Args:
            services: List of services to start (default: all)
        """
        available_services = ['realtime_classification', 'batch_processing']
        services = services or available_services
        
        for service in services:
            if service == 'realtime_classification':
                self._start_realtime_service()
            elif service == 'batch_processing':
                self._start_batch_service()
            else:
                self.logger.warning(f"Unknown service: {service}")
    
    def _start_realtime_service(self):
        """Start real-time classification service."""
        try:
            realtime_classifier = self.components['realtime_classifier']
            realtime_classifier.start_processing()
            self.services_started.append('realtime_classification')
            self.logger.info("Real-time classification service started")
        except Exception as e:
            self.logger.error(f"Failed to start real-time service: {e}")
    
    def _start_batch_service(self):
        """Start batch processing service (placeholder for scheduler integration)."""
        # This would integrate with a job scheduler like Celery, APScheduler, etc.
        self.logger.info("Batch processing service configured (integrate with scheduler)")
        self.services_started.append('batch_processing')
    
    def stop_services(self):
        """Stop all running services."""
        if 'realtime_classification' in self.services_started:
            self.components['realtime_classifier'].stop_processing()
            self.services_started.remove('realtime_classification')
        
        self.logger.info("All services stopped")
    
    def classify_paper(self, paper_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Classify a single paper using the AI engine.
        
        Args:
            paper_data: Paper metadata dictionary
            
        Returns:
            Classification results
        """
        return self.components['classification_engine'].classify_paper(paper_data)
    
    def get_user_recommendations(self, user_id: str, count: int = 20) -> list:
        """
        Get personalized recommendations for a user.
        
        Args:
            user_id: User identifier
            count: Number of recommendations
            
        Returns:
            List of recommendations
        """
        return self.components['recommendation_engine'].get_recommendations(
            user_id, count=count
        )
    
    def process_user_feedback(self, user_id: str, paper_id: str, 
                            feedback_type: str, feedback_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Process user feedback for learning.
        
        Args:
            user_id: User identifier
            paper_id: Paper identifier
            feedback_type: Type of feedback
            feedback_data: Feedback data
            
        Returns:
            Processing results
        """
        return self.components['feedback_system'].process_feedback(
            user_id, paper_id, feedback_type, feedback_data
        )
    
    def run_daily_batch_processing(self) -> Dict[str, Any]:
        """
        Run daily batch processing job.
        
        Returns:
            Processing results
        """
        batch_processor = self.components['batch_processor']
        return batch_processor.process_daily_papers()
    
    def get_system_status(self) -> Dict[str, Any]:
        """Get comprehensive system status."""
        status = {
            'application_status': 'running' if self.is_running else 'stopped',
            'services_started': self.services_started.copy(),
            'database_connected': self.db is not None,
            'components_initialized': len(self.components),
            'timestamp': datetime.utcnow().isoformat()
        }
        
        # Get component-specific statistics
        try:
            if 'realtime_classifier' in self.components:
                status['realtime_stats'] = self.components['realtime_classifier'].get_realtime_stats()
            
            if 'recommendation_engine' in self.components:
                status['recommendation_stats'] = self.components['recommendation_engine'].get_recommendation_stats()
            
            if 'batch_processor' in self.components:
                status['batch_stats'] = self.components['batch_processor'].get_processing_stats()
                
        except Exception as e:
            self.logger.error(f"Error getting component statistics: {e}")
        
        return status
    
    def run(self):
        """Run the application main loop."""
        self.is_running = True
        
        try:
            self.logger.info("Starting AI Classification Application")
            
            # Start default services
            self.start_services(['realtime_classification'])
            
            self.logger.info("AI Classification Application is running")
            self.logger.info("Press Ctrl+C to stop")
            
            # Main loop
            while self.is_running:
                time.sleep(1)
                
        except KeyboardInterrupt:
            self.logger.info("Received shutdown signal")
        except Exception as e:
            self.logger.error(f"Application error: {e}")
        finally:
            self._shutdown()
    
    def _shutdown(self):
        """Graceful shutdown of the application."""
        self.logger.info("Shutting down AI Classification Application...")
        
        # Stop services
        self.stop_services()
        
        # Close database connection
        if self.db:
            try:
                self.db.disconnect()
            except:
                pass
        
        self.is_running = False
        self.logger.info("Application shutdown complete")


def main():
    """Main entry point for the application."""
    parser = argparse.ArgumentParser(description='AI Classification Engine for ArXiv Platform')
    parser.add_argument('--config', '-c', help='Configuration file path')
    parser.add_argument('--mode', '-m', choices=['run', 'batch', 'classify'], 
                       default='run', help='Application mode')
    parser.add_argument('--paper-file', help='Paper data file for classification mode')
    parser.add_argument('--user-id', help='User ID for recommendation mode')
    
    args = parser.parse_args()
    
    # Initialize application
    app = AIClassificationApplication(config_path=args.config)
    
    try:
        if args.mode == 'run':
            # Run application with services
            app.run()
            
        elif args.mode == 'batch':
            # Run batch processing
            print("Running daily batch processing...")
            result = app.run_daily_batch_processing()
            print(f"Batch processing complete: {result['successful_classifications']} papers processed")
            
        elif args.mode == 'classify':
            # Classify papers from file
            if not args.paper_file:
                print("Error: --paper-file required for classify mode")
                sys.exit(1)
            
            try:
                with open(args.paper_file, 'r') as f:
                    papers_data = json.load(f)
                
                if not isinstance(papers_data, list):
                    papers_data = [papers_data]
                
                print(f"Classifying {len(papers_data)} papers...")
                
                for paper_data in papers_data:
                    result = app.classify_paper(paper_data)
                    print(f"Paper {paper_data.get('arxiv_id', 'unknown')}: {len(result.get('semantic_topics', []))} topics found")
                
            except Exception as e:
                print(f"Error processing paper file: {e}")
                sys.exit(1)
        
        else:
            print(f"Unknown mode: {args.mode}")
            sys.exit(1)
            
    except Exception as e:
        print(f"Application error: {e}")
        sys.exit(1)


if __name__ == '__main__':
    main()